/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package queryOpt;

import java.util.ArrayList;

public class planSet {

    private ArrayList<subPlan> allPlan;   //stores all subplans with size from 1 to this.num.
    private ArrayList<Double> selectivity;//Selectivity arraylist, for example [0.1,0.2,0.3,0.6].
    private int num;                      //the number of terms to be optimized.

    public planSet(int number) {
        this.num = number;
        //System.out.println((1<<this.num)-1);
        this.allPlan = new ArrayList<subPlan>(1 << this.num);
        System.out.println("allPlan size");
        System.out.println(1 << this.num);
    }

    public void setSelectivity(ArrayList<Double> select) {
        this.selectivity = new ArrayList<Double>();
        for (Integer i = 0; i < this.num; i++) {
            this.selectivity.add(select.get(i));
            //System.out.println(this.selectivity.get(i));
        }
    }

    public void initSubSet(ArrayList<Double> select) {
        this.setSelectivity(select);
        //System.out.print((1<<this.num)-1);
        for (int i = 0; i < ((1 << this.num) - 1); i++) {
            //System.out.println(i);
            subPlan tempPlan = new subPlan();
            tempPlan.subPlan(i + 1, this.num);
            //System.out.println("hi");
            tempPlan.initialization(config.Get_r(), config.Get_l(), config.Get_f(), config.Get_t(), config.Get_m(), this.selectivity, config.Get_a());
            //System.out.println("hi2");
            this.allPlan.add(tempPlan);
        }
        for (int j = 0; j < this.allPlan.size(); j++) {
            for (int i = 0; i < this.allPlan.get(j).getBitMap().length; i++) {
                //System.out.print(this.allPlan.get(j).getBitMap()[i] + " ");
            }  /*
            System.out.print("length: "+this.allPlan.get(j).getNum()+" ,cMetric: "+this.allPlan.get(j).getCMetric()+" ,dMetric: "+this.allPlan.get(j).getDMetric()+" ,seq: "+this.allPlan.get(j).getSeq());
            System.out.print("branch or not: "+this.allPlan.get(j).getBranchSign()+" ,best cost: "+this.allPlan.get(j).getBestCost()+" ,p: "+this.allPlan.get(j).getP()+" ,q: "+this.allPlan.get(j).getQ());
            System.out.print("\n");
            System.out.print("NoBranch: "+this.allPlan.get(j).getNoBranchCost()+" ,branchand: "+this.allPlan.get(j).getBranchingAndCost()+" ,logicAnd: "+this.allPlan.get(j).getLogicAndCost());
            System.out.print("\n");
            System.out.println("j: "+j+" ,seq: "+this.allPlan.get(j).getSeq());
            System.out.print("\n");
             */
        }

    }

    public Integer unionBitMap(Integer a1, Integer a2) {
        Integer temp = 0;
        temp = a1 + a2 + 1;
        return temp;
    }

    public Integer cMetricIden(Integer a1, Integer a2) {
        Integer temp = 1;
        subPlan temp1=this.allPlan.get(a1);
        while(temp1.getLeftChild()!=null)
        {temp1=temp1.getLeftChild();
        }

            if (temp1.getP() <= this.allPlan.get(a2).getP() && temp1.getCMetric() <= this.allPlan.get(a2).getCMetric()) {
                temp = 0;
            }
       
        return temp;
    }

    public Integer dMetricIden(Integer a1, Integer a2) {
        Integer temp = 1;
        subPlan temp1=this.allPlan.get(a1);
        if(temp1.getLeftChild()==null)
        {
         if (this.allPlan.get(a2).getP() < 0.5 && temp1.getP() < this.allPlan.get(a2).getP() && temp1.getDMetric() < this.allPlan.get(a2).getDMetric()) {
            temp = 0;
        }
        }
        while(temp1!=null)
        {
            if(temp1.getLeftChild()!=null)
            { if (this.allPlan.get(a2).getP() < 0.5 && temp1.getLeftChild().getP() < this.allPlan.get(a2).getP() && temp1.getLeftChild().getDMetric() < this.allPlan.get(a2).getDMetric()) {
            temp = 0;
            }
           
         
        }
           else
              { if (this.allPlan.get(a2).getP() < 0.5 && temp1.getP() < this.allPlan.get(a2).getP() && temp1.getDMetric() < this.allPlan.get(a2).getDMetric()) {
            temp = 0;
        }
              }
             temp1=temp1.getRightChild();
        }
       

        return temp;
    }
    //costEvaluation computes the context in part(2) of the algorithm 4.11 in the paper.

    public void costEvaluation(Integer a, Integer b) {
         if (this.cMetricIden(a, b) == 1 && this.dMetricIden(a, b) == 1) {  //eliminate some subplans using Cmetric and Dmetric
        Double tempC = 0.0;
        //fcost(E)+mq+pC,
        System.out.println("b:" + this.allPlan.get(b).getSeq() + "cost:" + this.allPlan.get(b).getBestCost());
        System.out.println("a:" + this.allPlan.get(a).getSeq() + "cost:" + this.allPlan.get(a).getBestCost());

        tempC = this.allPlan.get(b).getFCost() + this.allPlan.get(b).getQ() * config.Get_m() + this.allPlan.get(b).getP() * this.allPlan.get(a).getBestCost();
        System.out.println("tempC: " + tempC + " ,original best: " + this.allPlan.get(this.unionBitMap(a, b)).getBestCost());

                if (tempC < this.allPlan.get(this.unionBitMap(a, b)).getBestCost()) {
                System.out.println("found better plan.");
                this.allPlan.get(this.unionBitMap(a, b)).setLeftChild(this.allPlan.get(b));//no nobranch best plan
                this.allPlan.get(this.unionBitMap(a, b)).setRightChild(this.allPlan.get(a));


                this.allPlan.get(this.unionBitMap(a, b)).setBestCost(tempC);
                System.out.println("optimize seq: " + this.allPlan.get(this.unionBitMap(a, b)).getSeq());
                System.out.println("leftchild is: " + this.allPlan.get(this.unionBitMap(a, b)).getLeftChild().getSeq() + " ,rightchild is: " + this.allPlan.get(this.unionBitMap(a, b)).getRightChild().getSeq());
        }
 







          }
    }

    // Performs the DP algorithm over all subsets according to the increasing order specified in the paper.Finally, the last subplan in planset will be optimal and is returned to Main.
    public subPlan DPCalculation() {
        for (Integer i = 0; i < ((1 << this.num) - 2); i++) {
            System.out.println("i: " + i + " sequence;" + this.allPlan.get(i).getSeq());

            //Get the maximum subset of S' that S and S' have no common terms.
       

            //Traversing all s' that has no common terms with s using bitmap.
            for (Integer j = 0; j < ((1 << this.num) - 2); j++) {
                Integer flag = this.allPlan.get(i).checkCommon(this.allPlan.get(j));
                //if checkCommon returns 1, s' has no common term with s.
                if (flag == 1) {
                    System.out.println("comparable. i: " + i + " j:" + j);
                    System.out.println("seq of i: " + this.allPlan.get(i).getSeq() + " ,seq of j: " + this.allPlan.get(j).getSeq());
                    this.costEvaluation(i, j);  //compare the cost after union this two & terms and update whenever a better plan is found.
                }
            }
            System.out.print("\n");
        }
      //  System.out.println(this.getResultPlan().getRightChild().getBestCost2());
     this.getResultPlan().findRightest(true);
        return this.getResultPlan();
    }

    // return the last subplan in planset, which is the optimal plan for this query after DP algorithm.
    public subPlan getResultPlan() {
        return this.allPlan.get(this.allPlan.size() - 1);
    }
}
